import * as ol from "ol";
import { Geometry, Point } from "ol/geom";
import * as Layer from "ol/layer";
import * as Source from "ol/source";
import * as keys from "./keys";
import { log } from "./log";
import { getMap } from "./instance";
import { RenderHeatmapLayerOptions } from "./types";
import { parseLngLat } from "./utils";
import { excludeProperties } from "@utils";

/**
 * @description: 渲染热力图图层
 * @private
 * @param {RenderHeatmapLayerOptions} options 配置项
 * @returns {Layer.Heatmap}
 */
export const renderHeatmapLayer = (
  options: RenderHeatmapLayerOptions
): Layer.Heatmap => {
  const mapInstance = getMap();
  if (!mapInstance) {
    throw new Error("地图实例未初始化");
  }
  const { type: layerType, visible = true, max, data } = options;
  let maxValue = Math.max(...data.map(({ value = 1 }) => value));
  maxValue = typeof max === "number" ? Math.min(maxValue, max) : maxValue;
  let layer = mapInstance
    .getAllLayers()
    .find((item) => item.get(keys.LAYER_TYPE_KEY) === layerType) as
    | Layer.Heatmap
    | undefined;
  if (!(layer instanceof Layer.Heatmap)) {
    layer = new Layer.Heatmap({
      source: new Source.Vector<ol.Feature<Geometry>>(),
      ...excludeProperties(options, ["type", "data", "max"]),
    });
    layer.set(keys.LAYER_TYPE_KEY, layerType);
    mapInstance.addLayer(layer);
  }

  log("Render Heatmap Layer", options);

  layer.getSource()?.clear();
  layer.getSource()?.addFeatures(
    data
      .map((item) => ({ ...item, position: parseLngLat(item.position) }))
      .filter(({ position }) => position !== undefined)
      .map(
        ({ position, value = 1 }) =>
          new ol.Feature({
            geometry: new Point(position as number[]),
            weight: Math.max(Math.min(value / maxValue, 1), 0),
          })
      )
  );
  layer.setVisible(visible);

  return layer;
};

/**
 * @description: 显示或渲染热力图图层
 * @private
 * @param {RenderHeatmapLayerOptions} options 配置项
 * @returns {Layer.Heatmap}
 */
export const showOrRenderHeatmapLayer = (
  options: RenderHeatmapLayerOptions
): Layer.Heatmap => {
  const mapInstance = getMap();
  if (!mapInstance) {
    throw new Error("地图实例未初始化");
  }
  const { type: layerType, visible = true } = options;
  const layer = mapInstance
    .getAllLayers()
    .find((item) => item.get(keys.LAYER_TYPE_KEY) === layerType) as
    | Layer.Heatmap
    | undefined;
  if (layer instanceof Layer.Heatmap) {
    log("Change Heatmap Layer Visible", options);
    layer.setVisible(visible);
    return layer;
  }

  return renderHeatmapLayer(options);
};
